import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;

public class LLdriver {
	private static boolean verbose;

	public static void main(String[] args){
		String scannerFile, grammarFile, parseTableFile;
		LLgenerator parserGenerator;
		LinkedList<String> input;

		if(args.length == 2){
			// Assign any input parameter
			grammarFile = args[0];
			parseTableFile = args[1];
			scannerFile = null;
			verbose = false;
		}
		else{
			throw new RuntimeException("\n Wrong input parameters to LLparser.java.  Input parameters are: \n"
					+"   Scanner File Name \n"
					+"   Grammar File Name \n"
					+"   Parse Table File Name (to save to)");
		}		

		try{
			String line;
			String lineTokens[], terminalTokens[], nonterminalTokens[], startToken;
			
			FileInputStream fstream = new FileInputStream(grammarFile);
			DataInputStream dstream = new DataInputStream(fstream); 
			BufferedReader br = new BufferedReader(new InputStreamReader(dstream));

			line = br.readLine();
			line = removeMultipleSpaces(line);
			lineTokens = line.trim().split(" ");
			if (!lineTokens[0].equals("%Tokens"))
				throw new RuntimeException("\n error.");
			terminalTokens = new String[lineTokens.length-1];
			for(int i=0; i<terminalTokens.length; i++)
				terminalTokens[i] = lineTokens[i+1].trim();

			line = br.readLine();
			line = removeMultipleSpaces(line);
			lineTokens = line.trim().split(" ");
			if (!lineTokens[0].equals("%Non-terminals"))
				throw new RuntimeException("\n error.");
			nonterminalTokens = new String[lineTokens.length-1];
			for(int i=0; i<nonterminalTokens.length; i++)
				nonterminalTokens[i] = lineTokens[i+1].trim();

			line = br.readLine();
			line = removeMultipleSpaces(line);
			lineTokens = line.trim().split(" ");
			if (!lineTokens[0].equals("%Start"))
				throw new RuntimeException("\n error.");
			startToken = lineTokens[1].trim();
		
			parserGenerator = new LLgenerator(terminalTokens,nonterminalTokens,startToken);

			line = br.readLine();
			line = removeMultipleSpaces(line);
			lineTokens = line.trim().split(" ");
			if (!lineTokens[0].equals("%Rules"))
				throw new RuntimeException("\n error.");

			String rule;
			String productionRules[];
			String splitString[];

			while( (line = br.readLine()) != null )
			{
				line = removeMultipleSpaces(line);
				splitString = line.split(":"); 					
				rule = splitString[0].trim(); 					
				productionRules = splitString[1].split("\\|");	
				for(String productionRule : productionRules)
					parserGenerator.addRule(rule, productionRule.trim().split(" "));
			}

			dstream.close();
		}
		catch(IOException e){
			throw new RuntimeException("\n Grammar file read failed.");
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			throw new RuntimeException("\n Grammar file malformed.");			
		}

		parserGenerator.buildParseTable();
		
		try{
			parserGenerator.saveParseTable(parseTableFile);
		}
		catch(IOException e){
			throw new RuntimeException("\n Save parse table failed.");
		}

		if(scannerFile==null){
			System.out.println("Parse table saved at: "+parseTableFile);
			return;
		}

		//load data
		try
		{
			String line;
			String lineTokens[];

			// Set up data input
			FileInputStream fstream = new FileInputStream(scannerFile);
			DataInputStream dstream = new DataInputStream(fstream); 
			BufferedReader br = new BufferedReader(new InputStreamReader(dstream));

			// Set up input list
			input = new LinkedList<String>();

			// Read line
			line = br.readLine();
			line = removeMultipleSpaces(line);

			if(line.contains("$"))
				throw new RuntimeException("\n Cant use $.");							
			if( br.readLine() != null ) // File should only be one line long
				throw new RuntimeException("\n Scanner file greater than one line long.");

			// end file read
			dstream.close();

			lineTokens = line.split(" ");			
			for(String token : lineTokens)
			{
				input.addLast(token);
			}
			// Make sure input ends with $
			input.addLast("$");

		}
		catch(IOException e){
			throw new RuntimeException("\n Failed");
		}

		LLparser.parse(input, parserGenerator.getParseTable());			
		System.out.println("Sucess");
	}

	private static String removeMultipleSpaces(String string){
		String oldString;

		do
		{
			oldString = string;
			string = string.replace("  ", " ");
		}while( !string.equals(oldString) );

		return string;
	}

	public static boolean verboseOn(){
		return verbose;
	}
}
